#include "stdafx.h"
#include "../Common/ServiceLocator/ServiceLocator.h"
#include "../Common/PluginManager/PluginManager.h"
#include "../StartupTool/Environment/Environment.h"
#include "UserInterface/UserInterface.h"
#include "Direct3D9Hijack/Direct3D9Hijack.h"
#include "DirectInput8Hijack/DirectInput8Hijack.h"

IServiceLocator* gr_ServiceLocator_ = NULL;
HHOOK gh_GlobalHook = NULL;


void Start(HMODULE ah_Module)
{		
	if (gr_ServiceLocator_ == NULL)
	{
		gr_ServiceLocator_ = new k_ServiceLocator();

		gr_ServiceLocator_->AddService(new k_PluginManager());
		gr_ServiceLocator_->AddService(new k_Environment(ah_Module));
		gr_ServiceLocator_->AddService(new k_Direct3D9Hijack());
		gr_ServiceLocator_->AddService(new k_DirectInput8Hijack());
		gr_ServiceLocator_->AddService(new k_UserInterface());
		
		gr_ServiceLocator_->InitializeServices();
	}
}


void End()
{	
	if (gr_ServiceLocator_ != NULL)
	{
		gr_ServiceLocator_->DeinitializeServices();
		delete gr_ServiceLocator_;
		gr_ServiceLocator_ = NULL;
	}
}


BOOL ProcessAttach(HMODULE hDll)
{
	::Start(hDll);

	return TRUE;
}

BOOL ProcessDetach(HMODULE hDll)
{
	::End();

	return TRUE;
}


BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 )
{
    switch(ul_reason_for_call)
	{
		case DLL_PROCESS_ATTACH: return ProcessAttach(hModule);
		case DLL_PROCESS_DETACH: return ProcessDetach(hModule);
	}
	return TRUE;
}


static LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam) 
{
	/*CWPSTRUCT *lr_WndProc_ = reinterpret_cast<CWPSTRUCT *>(lParam);
	if (lr_WndProc_) 
	{
		switch (lr_WndProc_->message) 
		{
			case WM_QUIT:
				PrintLog(L"C:\\Walhall\\Walhall.log", L"Exit...\n")
				::End();
				break;
			default:
				break;
		}
	}*/
	return CallNextHookEx(gh_GlobalHook, nCode, wParam, lParam);
}


extern "C" __declspec(dllexport) void __cdecl RemoveHooks()
{
	if (gh_GlobalHook != NULL)
	{
		::UnhookWindowsHookEx(gh_GlobalHook);
		gh_GlobalHook = NULL;
	}
}


extern "C" __declspec(dllexport) void __cdecl InstallHooks()
{
	HMODULE lh_Self = NULL;
	::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (wchar_t *) &InstallHooks, &lh_Self);
	if (lh_Self == NULL) 
	{
		//PrintLog(L"Walhall: Unable to find module while installing hook.")
	} 
	else 
	{
		gh_GlobalHook = ::SetWindowsHookEx(WH_CALLWNDPROC, CallWndProc, lh_Self, 0);
		if (gh_GlobalHook == NULL)
		{
			//PrintLog(L"Walhall: Unable to install window procedure hook.");
		}
	}
}
